Spring Security হল একটি শক্তিশালী ফ্রেমওয়ার্ক যা Spring ভিত্তিক অ্যাপ্লিকেশনগুলোতে নিরাপত্তা ব্যবস্থা প্রদান করে। RESTful API-তে নিরাপত্তা যোগ করার জন্য Spring Security ব্যবহার করা হয়, যেখানে Authentication, Authorization, CSRF Protection, এবং আরও অনেক নিরাপত্তা কার্যক্রম পরিচালিত হয়।
এখানে Spring Security ব্যবহারের মাধ্যমে REST API-এর জন্য Authentication ও Authorization কনফিগারেশন দেওয়া হয়েছে, যাতে আমরা JWT (JSON Web Token) ব্যবহার করে নিরাপত্তা ব্যবস্থা ইমপ্লিমেন্ট করতে পারি।
Spring Security with JWT Authentication for REST API: উদাহরণ
Step 1: Dependencies
প্রথমে, আপনাকে আপনার pom.xml ফাইলে প্রয়োজনীয় ডিপেন্ডেন্সি যোগ করতে হবে।
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.11.5</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
</dependencies>
Step 2: JWT Utility Class
JWT Utility Class তৈরি করা হবে, যা Token Generation এবং Token Validation পরিচালনা করবে।
import io.jsonwebtoken.*;
import java.util.Date;
import org.springframework.stereotype.Component;
@Component
public class JwtUtil {
private String SECRET_KEY = "your-256-bit-secret-key";
private final int EXPIRATION_TIME = 1000 * 60 * 60 * 10; // 10 Hours
public String generateToken(String username) {
return Jwts.builder()
.setSubject(username)
.setIssuedAt(new Date())
.setExpiration(new Date(System.currentTimeMillis() + EXPIRATION_TIME))
.signWith(SignatureAlgorithm.HS256, SECRET_KEY)
.compact();
}
public String extractUsername(String token) {
return Jwts.parserBuilder()
.setSigningKey(SECRET_KEY)
.build()
.parseClaimsJws(token)
.getBody()
.getSubject();
}
public boolean isTokenExpired(String token) {
return getExpirationDateFromToken(token).before(new Date());
}
public Date getExpirationDateFromToken(String token) {
return Jwts.parserBuilder()
.setSigningKey(SECRET_KEY)
.build()
.parseClaimsJws(token)
.getBody()
.getExpiration();
}
public boolean validateToken(String token, String username) {
return (username.equals(extractUsername(token)) && !isTokenExpired(token));
}
}
Step 3: Authentication Filter
JWT Token যাচাই করার জন্য Authentication Filter তৈরি করা হবে। এটি প্রতিটি HTTP রিকোয়েস্টের হেডারে পাঠানো JWT টোকেন যাচাই করবে।
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import java.io.IOException;
@Component
public class JwtAuthenticationFilter extends OncePerRequestFilter {
@Autowired
private JwtUtil jwtUtil;
@Autowired
private UserDetailsService userDetailsService;
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
final String authHeader = request.getHeader("Authorization");
String username = null;
String token = null;
if (authHeader != null && authHeader.startsWith("Bearer ")) {
token = authHeader.substring(7);
username = jwtUtil.extractUsername(token);
}
if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
UserDetails userDetails = userDetailsService.loadUserByUsername(username);
if (jwtUtil.validateToken(token, userDetails.getUsername())) {
UsernamePasswordAuthenticationToken authToken =
new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
SecurityContextHolder.getContext().setAuthentication(authToken);
}
}
filterChain.doFilter(request, response);
}
}
Step 4: Spring Security Configuration
Spring Security Configuration তৈরি করা হবে যাতে JWT Filter এবং Custom Authentication Handler যুক্ত করা যায়।
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Autowired
private JwtAuthenticationFilter jwtAuthenticationFilter;
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeHttpRequests()
.requestMatchers("/auth/**").permitAll() // Allow login without authentication
.anyRequest().authenticated() // Other requests need authentication
.and()
.addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);
return http.build();
}
}
Explanation:
csrf().disable(): REST API-তে CSRF সাধারণত নিষ্ক্রিয় করা হয়, কারণ API কল স্টেটলেস।addFilterBefore: CustomJwtAuthenticationFilterSpring Security filter chain-এ যুক্ত করা হয়েছে, যাতে টোকেন যাচাই করা হয়।
Step 5: Authentication Controller
লগইন করতে এবং JWT Token পেতে একটি API তৈরি করা হবে।
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/auth")
public class AuthController {
@Autowired
private AuthenticationManager authenticationManager;
@Autowired
private JwtUtil jwtUtil;
@PostMapping("/login")
public String login(@RequestBody AuthRequest authRequest) {
authenticationManager.authenticate(
new UsernamePasswordAuthenticationToken(authRequest.getUsername(), authRequest.getPassword())
);
return jwtUtil.generateToken(authRequest.getUsername());
}
}
class AuthRequest {
private String username;
private String password;
// Getters and Setters
}
Explanation:
loginMethod: ব্যবহারকারী যখন লগইন করবে, তখন JWT Token ইস্যু করা হবে।
Step 6: Accessing Protected Resources
আপনি নিরাপদ GET বা POST রিকোয়েস্ট করার জন্য JWT Token ব্যবহার করবেন। নিচে একটি উদাহরণ দেওয়া হয়েছে:
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class ApiController {
@GetMapping("/protected")
public String getProtectedData() {
return "This is a protected resource!";
}
}
এখানে /protected এন্ডপয়েন্টটি JWT Token যাচাই করবে এবং Token বৈধ হলে শুধুমাত্র এক্সেস পাওয়া যাবে।
Step 7: Testing with Postman
- প্রথমে
/auth/loginরিকোয়েস্ট দিয়ে JWT Token পেতে হবে। - তারপর এই JWT Token হেডারে পাঠিয়ে
/protectedএন্ডপয়েন্টে GET রিকোয়েস্ট পাঠাতে হবে।
Example:
Authorization Header:
Bearer <JWT_TOKEN>
Conclusion
এটি একটি সিম্পল JWT Authentication পদ্ধতি যেখানে Spring Security ব্যবহৃত হয়েছে REST API সুরক্ষিত করার জন্য। মূল পদ্ধতিগুলি ছিল:
- JWT Token Generation - লগইন করার সময় টোকেন তৈরি করা।
- JWT Token Validation - প্রতিটি রিকোয়েস্টের সাথে টোকেন যাচাই করা।
- Spring Security Configuration - টোকেন যাচাই করতে Spring Security ফিল্টার ব্যবহার করা।
এটি নিরাপদ REST API নির্মাণের জন্য একটি কার্যকরী পদ্ধতি।
Read more